import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig
} from 'axios';

import axios from 'axios';
import type { MyRequestConfig } from './type';

class Request {
  instance: AxiosInstance;

  constructor(config: MyRequestConfig) {
    this.instance = axios.create(config);

    // 只有当此实例的config中存在请求拦截器和响应拦截器存在时，才添加拦截器，起到实例级拦截的作用
    this.instance.interceptors.request.use(
      config.interceptors?.reqSuccessCallback,
      config.interceptors?.reqFailCallback
    );
    this.instance.interceptors.response.use(
      config.interceptors?.resSuccessCallback,
      config.interceptors?.resFailCallback
    );
  }

  request<T = any>(config: MyRequestConfig<T>) {
    // 单次请求拦截
    if (config.interceptors?.reqSuccessCallback) {
      config = config.interceptors.reqSuccessCallback(config as InternalAxiosRequestConfig);
    }

    return new Promise<T>((resolve, reject) => {
      // 调用axios的原生request方法
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.resSuccessCallback) {
            res = config.interceptors?.resSuccessCallback(res);
          }
          resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  get<T = any>(config: MyRequestConfig<T>): Promise<any>;
  get<T = any>(url: string): Promise<any>;
  get<T = any>(configOrUrl: MyRequestConfig<T> | string): Promise<any> {
    if (typeof configOrUrl === 'string') {
      const url = configOrUrl;
      return this.instance.request({
        method: 'get',
        url
      });
    } else {
      const config = configOrUrl as MyRequestConfig<T>;
      return this.instance.request({
        method: 'get',
        ...config
      });
    }
  }

  post<T = any>(configOrUrl: MyRequestConfig<T> | string): Promise<any>;
  post<T = any>(url: string): Promise<any>;
  post<T = any>(configOrUrl: MyRequestConfig<T> | string) {
    if (typeof configOrUrl === 'string') {
      const url = configOrUrl;
      return this.instance.request({
        method: 'post',
        url
      });
    } else {
      const config = configOrUrl as MyRequestConfig<T>;
      return this.instance.request({
        method: 'post',
        ...config
      });
    }
  }

  put<T = any>(configOrUrl: MyRequestConfig<T> | string): Promise<any>;
  put<T = any>(url: string): Promise<any>;
  put<T = any>(configOrUrl: MyRequestConfig<T> | string) {
    if (typeof configOrUrl === 'string') {
      const url = configOrUrl;
      return this.instance.request({
        method: 'put',
        url
      });
    } else {
      const config = configOrUrl as MyRequestConfig<T>;
      return this.instance.request({
        method: 'put',
        ...config
      });
    }
  }

  delete<T = any>(configOrUrl: MyRequestConfig<T> | string): Promise<any>;
  delete<T = any>(url: string): Promise<any>;
  delete<T = any>(configOrUrl: MyRequestConfig<T> | string) {
    if (typeof configOrUrl === 'string') {
      const url = configOrUrl;
      return this.instance.request({
        method: 'delete',
        url
      });
    } else {
      const config = configOrUrl as MyRequestConfig<T>;
      return this.instance.request({
        method: 'delete',
        ...config
      });
    }
  }

  patch<T = any>(configOrUrl: MyRequestConfig<T> | string): Promise<any>;
  patch<T = any>(url: string): Promise<any>;
  patch<T = any>(configOrUrl: MyRequestConfig<T> | string) {
    if (typeof configOrUrl === 'string') {
      const url = configOrUrl;
      return this.instance.request({
        method: 'patch',
        url
      });
    } else {
      const config = configOrUrl as MyRequestConfig<T>;
      return this.instance.request({
        method: 'patch',
        ...config
      });
    }
  }
}

export default Request;
